﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Analyzer = Lucene.Net.Analysis.Analyzer;
using Lucene.Net.Analysis;
using StandardAnalyzer = Lucene.Net.Analysis.Standard.StandardAnalyzer;
using Lucene.Net.Documents;
using Document = Lucene.Net.Documents.Document;
using Field = Lucene.Net.Documents.Field;
using IndexWriter = Lucene.Net.Index.IndexWriter;
using ParseException = Lucene.Net.QueryParsers.ParseException;
using QueryParser = Lucene.Net.QueryParsers.QueryParser;
using Directory = Lucene.Net.Store.Directory;
using RAMDirectory = Lucene.Net.Store.RAMDirectory;
using Version = Lucene.Net.Util.Version;
using IndexSearcher = Lucene.Net.Search.IndexSearcher;
using Query = Lucene.Net.Search.Query;
using ScoreDoc = Lucene.Net.Search.ScoreDoc;
using Store = Lucene.Net.Store;
using Could.Service;
using IO = System.IO;
using System.Diagnostics;
using Lucene.Net.Index;
using MySql.Data.MySqlClient;

namespace CatSentenceAnalyzer
{
    public class IndexServer
    {
        public string indextmsdir, indextdbdir;

        public NPClass  m_np;
        public int m_EnginxID;
        private ArrayList m_arrTmsResult, m_arrTdbResult;
        private Hashtable m_TdbHashT ;
        private Stopwatch m_sw;

        public IndexServer(){
            m_EnginxID = 0;
            m_TdbHashT = new Hashtable();
            m_arrTmsResult = new ArrayList();
            m_arrTdbResult = new ArrayList();
        }


        public void CommandExe()
        {
            int i; string key;
            if (m_np.DbS == null) return;
            indextmsdir = m_np.IndexTMSPath;
            indextdbdir = m_np.IndexTDBPath;
            m_EnginxID = m_np.EnginxID;
            m_np.transdata.TmsSearchLevel = 0;
            m_np.Total = 0;
            m_sw = new Stopwatch();
            m_sw.Start();
            try{
                switch (m_np.CommandCode)
                {
                    case 1:CreateTMSIndex();
                	    break;
                    case 2:
                        for (i = CLangSegment.MININDEXTYPE; i <= CLangSegment.MAXINDEXTYPE; i ++ )
                        {
                            key = GetTokens(m_np.transdata.OSentence, i);
                            if (SearchIndex(key, true))
                            {
                                m_np.transdata.TmsSearchLevel = i;
                                break;
                            }
                        }
                        break;
                    case 3:
                        if(DeleteTmsid())
                            DeleteIndex(true);
                        break;
                    case 4:
                        key = GetTokens(m_np.transdata.OSentence, CLangSegment.MININDEXTYPE);
                        if (SearchIndex(key, true)){
                            UpdateTMSIndex();                    
                        }else{
                            AddTMSIndex();
                        }
                        break;
                }
                m_sw.Stop();
                m_np.TmsTime = m_sw.ElapsedMilliseconds.ToString();
                if (m_np.CommandCode == 2 && (m_arrTmsResult.Count > 0))
                {
                    MaketransTMSdata();
                }

                //////////////////////////////////////////////////////////////////////////TDB
                m_sw.Reset(); m_sw.Start();
                switch (m_np.CommandCode)
                {
                    case 5:
                        CreateTDBIndex();
                	    break;
                    case 6:
                        if (DeleteTdbid())
                            DeleteIndex(false);
                        break;
                    case 7:
                        TdbSeek();
                        break;
                    case 8:
                        //key = GetTokens(m_np.transdata.Osentence, CLangSegment.MININDEXTYPE);
                        if (TdbSeek(m_np.transdata.OSentence, CLangSegment.MININDEXTYPE))
                        {
                            UpdateTDBIndex();
                        }
                        else
                        {
                            AddTDBIndex();
                        }
                        break;
                }

                m_sw.Stop();
                m_np.TdbTime = m_sw.ElapsedMilliseconds.ToString();
                if(m_np.CommandCode == 7 && m_arrTdbResult.Count>0){
                    MaketransTDBdata();
                }

            }
            catch (System.Exception e ){
                m_np.error = e.Message;
            }
        }

        private Boolean TdbSeek()
        {
            return TdbSeek(m_np.transdata.OSentence, CLangSegment.TDBCOLLTYPE);
        }

        private Boolean TdbSeek(string strtxt , int itype)
        {
            string key = ""; int sum = 0;
            CATSegAnalyzer sa = new CATSegAnalyzer(m_EnginxID, itype);
            System.IO.StringReader reader = new System.IO.StringReader(strtxt);

            TokenStream ts = sa.ReusableTokenStream("", reader);
            CATSegTokenizer cst = (ts as CATSegTokenizer);
             cst.GetSegment();
            ArrayList list = cst.m_MatchSumKey;
            for (int i = 0; i < list.Count; i++ )
            {
                key = list[i].ToString();
                if (SearchIndex(key, false))
                {
                    foreach (int k in m_TdbHashT.Keys)
                    {   
                        ArrayList arrlist = new ArrayList();
                        Hashtable sublist = m_TdbHashT[k] as Hashtable;
                        sum = 0;
                        if (itype == CLangSegment.MININDEXTYPE)
                        {
                            ArrayList al = new ArrayList(sublist.Keys);
                            arrlist = sublist[al[0]] as ArrayList;
                        }else{
                            if ((i + k - 1) < list.Count)
                            {
                                for (int z = 0; z < k; z++)
                                {
                                    sum += Convert.ToInt32(list[i + z]);
                                }
                                arrlist = sublist[sum] as ArrayList;
                            }
                        }

                        if(arrlist != null)
                        foreach (Tdb tdb in arrlist)
                        {
                            m_arrTdbResult.Add(tdb);
                        }
                    }
                } 
            }
            return m_arrTdbResult.Count>0;
        }

        private void TdbSeek(string key, int i, ArrayList list)
        {
            

        }
        private void Maketransdata()
        {
            MaketransTMSdata();
            MaketransTDBdata();
        }
        private void MaketransTDBdata()
        {
            TransData td = m_np.transdata;
            td.TdbTitle = "术语，获得|1|条结果,用时(|2|秒),匹配相关10个厂家";
            td.TdbTitle = td.TdbTitle.Replace("|1|", m_arrTdbResult.Count.ToString());
            td.TdbTitle = td.TdbTitle.Replace("|2|", ((Convert.ToSingle(m_np.TdbTime)) / 1000).ToString());
            //td.TdbResult = "<img src='http://localhost/catweb/assets/images/5.png'>" + "this's ：这是\n" + "解释：这是什么？\n" + "相关厂家:<a href='event:www.baidu.com' target='_blank'>百度<\a>";
            string tmp = td.TdbResult = "";
            string sample = "<li><font size='10' color='#000000'>|1|</font>\n<font size='10' color='#3399ff'>|2|</font></li>\n";
            for (int i = 0; i < m_arrTdbResult.Count; i++ )
            {
                Tdb tdb = m_arrTdbResult[i] as Tdb;
                tmp += sample.Replace( "|1|", tdb.oTerm);
                tmp = tmp.Replace("|2|", tdb.tTerm);
            }
            td.TmsResult = tmp;
        }
        private void MaketransTMSdata()
        {
            TransData td = m_np.transdata;
            td.TSentence = "";
            td.TmsTitle = ("匹配结果: 获得|1|条结果, 用时(|2|秒)");
            td.TmsTitle = td.TmsTitle.Replace("|1|", m_arrTmsResult.Count.ToString());
            td.TmsTitle = td.TmsTitle.Replace("|2|", ((Convert.ToSingle( m_np.TmsTime)) / 1000).ToString());
            string tmp = td.TmsResult = "";
            string sample = "<li><font size='13' color='#000000'>|1|</font>\n<font size='13' color='#3399ff'>|2|</font></li>\n";
            for (int i = 0; i < m_arrTmsResult.Count; i++ )
            {
                Tms tms = m_arrTmsResult[i] as Tms;
                tmp += sample.Replace( "|1|", tms.oText);
                tmp = tmp.Replace("|2|", tms.tText);
            }
            td.TmsResult = tmp;
        }

        public Boolean CreateTMSIndex()
        {   
            if( SqlDataBase.GetDocuments(m_np ,  m_np.DbS.tmsquery))
            {
                Store.Directory directory = IndexTmsDirectory;
                Analyzer analyzer = new CATSegAnalyzer(m_EnginxID, CLangSegment.TMSALLINDEXTYPE);
                IndexWriter writer = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);
                Single boost = 0f;
                try
                {
                    using (SqlDataBase.m_reader)
                    {
                        while (SqlDataBase.m_reader.Read())
                        {
                            boost = Convert.ToInt32(SqlDataBase.m_reader.GetValue(SqlDataBase.m_reader.GetOrdinal(SqlDataBase.USAGECOUT)).ToString());
                            Document doc = new Document();
                            doc.Add(new Field(SqlDataBase.IDFIELD, SqlDataBase.m_reader.GetValue(SqlDataBase.m_reader.GetOrdinal(SqlDataBase.IDFIELD)).ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
                            doc.Add(new Field(SqlDataBase.USAGECOUT, boost.ToString(), Field.Store.YES, Field.Index.NO));
                            doc.Add(new Field(SqlDataBase.TEXTFIELD, SqlDataBase.m_reader.GetValue(SqlDataBase.m_reader.GetOrdinal(m_np.textField)).ToString(), Field.Store.YES, Field.Index.NO));
                            doc.Add(new Field(SqlDataBase.INDEXFIELD, SqlDataBase.m_reader.GetValue(SqlDataBase.m_reader.GetOrdinal(m_np.indexField)).ToString(), Field.Store.YES, Field.Index.ANALYZED));
                            doc.SetBoost(boost);
                            writer.AddDocument(doc);
                            m_np.Total++;
                        }
                    }
                }
                catch (System.Exception) { }
                finally
                {
                    writer.Optimize();
                    writer.Close();
                    directory.Close();
                }
            }
            return true;
        }
        public Boolean CreateTDBIndex()
        {
            if (SqlDataBase.GetDocuments(m_np, m_np.DbS.tdbquery))
            {
                MySqlDataReader reader = SqlDataBase.m_reader; 
                Store.Directory directory = IndexTdbDirectory;
                Analyzer analyzer = new CATSegAnalyzer(m_EnginxID, CLangSegment.TDBALLINDEXTYPE);
                IndexWriter writer = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);
                Single boost = 0f;
                using(SqlDataBase.m_reader)
                {
                    while (SqlDataBase.m_reader.Read())
                    {
                        boost = Convert.ToInt32(SqlDataBase.m_reader.GetValue(SqlDataBase.m_reader.GetOrdinal(SqlDataBase.WLENFIELD)).ToString());
                        Document doc = new Document();
                        doc.Add(new Field(SqlDataBase.IDFIELD, reader.GetValue(reader.GetOrdinal(SqlDataBase.IDFIELD)).ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
                        doc.Add(new Field(SqlDataBase.SUMFIELD, reader.GetValue(reader.GetOrdinal(SqlDataBase.SUMFIELD)).ToString(), Field.Store.YES, Field.Index.NO));
                        doc.Add(new Field(SqlDataBase.WLENFIELD, boost.ToString(), Field.Store.YES, Field.Index.NO));
                        doc.Add(new Field(SqlDataBase.TEXTFIELD, reader.GetValue(reader.GetOrdinal(m_np.tTerm)).ToString(), Field.Store.YES, Field.Index.NO));
                        doc.Add(new Field(SqlDataBase.INDEXFIELD, reader.GetValue(reader.GetOrdinal(m_np.oTerm)).ToString(), Field.Store.YES, Field.Index.ANALYZED));
                        doc.SetBoost(boost);
                        writer.AddDocument(doc);
                        m_np.Total++;
                    }
                }

                writer.Optimize();
                writer.Close();
                directory.Close();
            }
            return true;
        }

        private string GetTokens( string text, int segtype)
        {
            string tmp = "";
            CATSegAnalyzer sa = new CATSegAnalyzer(m_EnginxID, segtype);
            System.IO.StringReader reader = new System.IO.StringReader(text);

            TokenStream ts = sa.ReusableTokenStream("", reader);
            Token tk;
            while ((tk = ts.Next()) != null)
            {
                tmp +=tk.TermText() + " ";
            }
            return tmp;
        }

        public Boolean SearchIndex( string key , Boolean istms)
        {
            ArrayList arr;
            Store.Directory directory ;
            if (istms)
            {
                arr = m_arrTmsResult;
                directory = IndexTmsDirectory;
            }
            else
            {
                //arr = m_arrTdbResult;
                directory = IndexTdbDirectory;
            }

            IndexSearcher isearcher = new IndexSearcher(directory, true); // read-only=true
            WhitespaceAnalyzer analyzer = new WhitespaceAnalyzer();
            QueryParser parser = new QueryParser(Version.LUCENE_29, SqlDataBase.INDEXFIELD, analyzer);
            Query query = parser.Parse( key );
            ScoreDoc[] hits = isearcher.Search(query, null, 100).scoreDocs;

            m_TdbHashT = new Hashtable();
            Hashtable sublist; ArrayList subarr = null;
            for (int i = 0; i < hits.Length; i++)
            {
                Document hitDoc = isearcher.Doc(hits[i].doc);
                if (istms)
                {
                    Tms tms = new Tms();
                    tms.ID = hitDoc.Get(SqlDataBase.IDFIELD);
                    tms.oText = hitDoc.Get(SqlDataBase.INDEXFIELD);
                    tms.tText = hitDoc.Get(SqlDataBase.TEXTFIELD);
                    m_arrTmsResult.Add(tms);
                }else{
                    Tdb tdb = new Tdb();
                    tdb.ID = hitDoc.Get(SqlDataBase.IDFIELD);
                    tdb.oTerm = hitDoc.Get(SqlDataBase.INDEXFIELD);
                    tdb.tTerm = hitDoc.Get(SqlDataBase.TEXTFIELD);
                    tdb.WordLen =Convert.ToInt32( hitDoc.Get(SqlDataBase.WLENFIELD) );
                    tdb.SumKey = Convert.ToInt32( hitDoc.Get(SqlDataBase.SUMFIELD) );
                    //m_arrTdbResult.Add(tdb);
                    
                    if ( m_TdbHashT.ContainsKey( tdb.WordLen ))
                    {
                        sublist = m_TdbHashT[tdb.WordLen] as  Hashtable;
                        if (!sublist.ContainsKey(tdb.SumKey))
                        {
                            subarr = new ArrayList();
                            subarr.Add(tdb);
                            sublist.Add(tdb.SumKey, subarr);
                        }else{
                            subarr = sublist[tdb.SumKey] as ArrayList;
                            subarr.Add(tdb);
                        }
                    }else{
                        sublist = new Hashtable();
                        subarr = new ArrayList();
                        subarr.Add(tdb);
                        sublist.Add(tdb.SumKey, subarr);
                        m_TdbHashT.Add(tdb.WordLen, sublist);
                    }
                }
            }
            isearcher.Close();
            directory.Close();
            m_np.Total = hits.Length;
            return m_np.Total > 0;
        }
 
        public Boolean DeleteIndex( Boolean istms)
        {
            int id = m_np.transdata.TmsID;
            if (id > 0)
            {
                Store.Directory directory ;
                if (istms) directory = IndexTmsDirectory;
                else directory = IndexTdbDirectory;

                Analyzer analyzer = new WhitespaceAnalyzer();
                IndexWriter modifier = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);
                Term term = new Term(SqlDataBase.IDFIELD, id.ToString());
                modifier.DeleteDocuments(term);
                modifier.Commit(); // flush();
                modifier.Close();
                directory.Close();
                m_np.Total = 1;
            }
            return true;
        }

        private Boolean DeleteTmsid(){
            return SqlDataBase.DeleteDocumentID(m_np, m_np.DbS.tmstable);
        }

        private Boolean DeleteTdbid(){
            return SqlDataBase.DeleteDocumentID(m_np, m_np.DbS.tdbtable);
        }

        public Boolean UpdateTDBIndex(){
            Tdb tdb = m_arrTdbResult[0] as Tdb;
            if (m_np.transdata.TSentence != tdb.tTerm)
            {
                if (SqlDataBase.UpdateDocument_TDB(m_np , tdb ))
                {

                    Store.Directory directory = IndexTdbDirectory;
                    Analyzer analyzer = new CATSegAnalyzer(m_EnginxID, CLangSegment.TDBALLINDEXTYPE);
                    IndexWriter iwriter = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);
                    Document doc = new Document();
                    doc.Add(new Field(SqlDataBase.IDFIELD, tdb.ID, Field.Store.YES, Field.Index.NOT_ANALYZED));
                    doc.Add(new Field(SqlDataBase.SUMFIELD, tdb.SumKey.ToString(), Field.Store.YES, Field.Index.NO));
                    doc.Add(new Field(SqlDataBase.WLENFIELD, tdb.WordLen.ToString(), Field.Store.YES, Field.Index.NO));
                    doc.Add(new Field(SqlDataBase.TEXTFIELD,  m_np.transdata.TSentence, Field.Store.YES, Field.Index.NO));
                    doc.Add(new Field(SqlDataBase.INDEXFIELD, m_np.transdata.OSentence, Field.Store.YES, Field.Index.ANALYZED));
                    iwriter.UpdateDocument(new Term(SqlDataBase.IDFIELD, tdb.ID), doc);
                    iwriter.Close();
                    directory.Close();

                }
            }
            return true;
        }
        public Boolean UpdateTMSIndex()
        {
            
            Tms tms = m_arrTmsResult[0] as Tms;
            if (m_np.transdata.TSentence != tms.tText)//译文不同， 修改
            {
                if (SqlDataBase.UpdateDocument_TMS(m_np, tms))
                {
                    Store.Directory directory = IndexTmsDirectory;
                    Analyzer analyzer = new CATSegAnalyzer(m_EnginxID, CLangSegment.TMSALLINDEXTYPE);
                    IndexWriter iwriter = new IndexWriter(directory, analyzer, true, IndexWriter.MaxFieldLength.LIMITED);
                    Document doc = new Document();
                    doc.Add(new Field(SqlDataBase.IDFIELD, tms.ID, Field.Store.YES, Field.Index.NOT_ANALYZED));//NO
                    doc.Add(new Field(SqlDataBase.TEXTFIELD, m_np.transdata.TSentence, Field.Store.YES, Field.Index.NO));
                    doc.Add(new Field(SqlDataBase.INDEXFIELD, m_np.transdata.OSentence, Field.Store.YES, Field.Index.ANALYZED));
                    iwriter.UpdateDocument(new Term(SqlDataBase.IDFIELD, tms.ID), doc);
                    iwriter.Close();
                    directory.Close();
                }else{ //增加使用次数
                    SqlDataBase.UpdateDocument_UsageCount(m_np, tms);
                }
                m_np.Total = 1;
            }
            return true;
        }

        private Boolean AddTMSIndex()
        {
            int newid = SqlDataBase.AddNewDocument_TMS(m_np);
            if (newid >0 )
            {
                m_np.Total = 1;
                Store.Directory directory = IndexTmsDirectory;
                Analyzer analyzer = new CATSegAnalyzer(m_EnginxID, CLangSegment.TMSALLINDEXTYPE);
                IndexWriter writer = new IndexWriter(directory, analyzer, false, IndexWriter.MaxFieldLength.LIMITED);
                Document doc = new Document();
                doc.Add(new Field(SqlDataBase.IDFIELD, newid.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
                doc.Add(new Field(SqlDataBase.USAGECOUT, (0).ToString(), Field.Store.YES, Field.Index.NO));
                doc.Add(new Field(SqlDataBase.TEXTFIELD, m_np.transdata.TSentence , Field.Store.YES, Field.Index.NO));
                doc.Add(new Field(SqlDataBase.INDEXFIELD, m_np.transdata.OSentence , Field.Store.YES, Field.Index.ANALYZED));
                writer.AddDocument(doc);

                writer.Close();
                directory.Close();
            }
            return true;
        }


        private void GetTDBParamter( string[] parm)
        {
            string wordlen , sumkey;
            CATSegAnalyzer sa = new CATSegAnalyzer(m_EnginxID, CLangSegment.SUMKEYINDEXTYPE);//CLangSegment.MININDEXTYPE);
            System.IO.StringReader reader = new System.IO.StringReader(parm[2]);

            TokenStream ts = sa.ReusableTokenStream("", reader);
            CATSegTokenizer cst = (ts as CATSegTokenizer);
            cst.GetSegment();
            //hashkey = list[0] as string;
            sumkey = CLangSegment.SumKey(cst.m_MatchList[0].ToString()).ToString();
            wordlen = cst.GetSumKeyWordLength().ToString();
            parm[0] = sumkey; parm[1] = wordlen;
        }
        private Boolean AddTDBIndex()
        {
            string[] parm = new string[3];
            string wordlen="", sumkey, hashkey="";
            parm[2] = m_np.transdata.OSentence;
            GetTDBParamter(parm);
            sumkey = parm[0]; wordlen = parm[1];
            int newid = SqlDataBase.AddNewDocument_TDB(m_np , wordlen, sumkey, hashkey);
            if (newid > 0)
            {
                m_np.Total = 1;
                Store.Directory directory = IndexTdbDirectory;
                Analyzer analyzer = new CATSegAnalyzer(m_EnginxID, CLangSegment.TDBALLINDEXTYPE);
                IndexWriter writer = new IndexWriter(directory, analyzer, false, IndexWriter.MaxFieldLength.LIMITED);

                Document doc = new Document();
                doc.Add(new Field(SqlDataBase.IDFIELD, newid.ToString(), Field.Store.YES, Field.Index.NOT_ANALYZED));
                doc.Add(new Field(SqlDataBase.SUMFIELD, sumkey, Field.Store.YES, Field.Index.NOT_ANALYZED));
                doc.Add(new Field(SqlDataBase.WLENFIELD, wordlen, Field.Store.YES, Field.Index.NO));
                doc.Add(new Field(SqlDataBase.TEXTFIELD, m_np.transdata.TSentence, Field.Store.YES, Field.Index.NO));
                doc.Add(new Field(SqlDataBase.INDEXFIELD, m_np.transdata.OSentence, Field.Store.YES, Field.Index.ANALYZED));
                doc.SetBoost( Convert.ToSingle(wordlen));
                writer.AddDocument(doc);
                writer.Close();
                directory.Close();
            }
            return true;
        }
        private  Store.Directory IndexTmsDirectory{
            get{
                IO.DirectoryInfo info = new IO.DirectoryInfo(indextmsdir);
                Store.Directory directory = Store.FSDirectory.Open(info);
                return directory;
            }
        }
        private Store.Directory IndexTdbDirectory
        {
            get
            {
                IO.DirectoryInfo info = new IO.DirectoryInfo(indextdbdir);
                Store.Directory directory = Store.FSDirectory.Open(info);
                return directory;
            }
        }
    }
}
